才第九天,就開始不記得自己昨天寫了什麼東西、一天到晚翻閱前幾天的文補漏洞。正常乎?
在程式中設置欄位存放資料是件很奇妙的事情。
因為資料數目規模會讓這件事情的難度與意義變得完全不同。
比如程式內有三張圖片要存放,現在需要設置一個函數來取用圖片...(其實也可以不經由函數,但先假設要吧!)
Image img1;
Image img2;
Image img3;
Image getImage1(){
return img1;
}
Image getImage2(){
return img2;
}
Image getImage3(){
return img3;
}
這樣設計程式明顯不可行的地方是:萬一圖片變四張、變五張呢?難道要一直增加函數量嗎?(如果記得,「增加為了這種理由增加函數量其實會減低程式效能。」)
所以需要更有效率的做法...首先,一個函數就要能從所有圖片中去取得任何一張圖片、而且圖片數目還可以彈性增減,不用因為變多或變少就必須要回來修改函數內容。
Image img1;
Image img2;
Image img3;
Image getImage(int index){
(如果index為1)
return img1;
(如果index為2)
return img2;
(如果index為3)
return img3;
}
這樣修改只能達到「一個函數就要能從所有圖片中去取得任何一張圖片」,但「圖片數目還可以彈性增減,不用因為變多或變少就必須要回來修改函數內容」這點做不到。
這時候要從根本上改變資料欄位的形式,為了做到這點,就要使用Array/Lisr(矩陣或陣列)。
所謂的Array/List在概念上主要是「用一個資料欄位紀錄多筆資料」。
Flutter的程式碼看起來會長這樣...(其實大家已經在SDK建立的基本範例中看過,在MyHomePageState這個物件中。)
<Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
]
這個Array/List並沒有設置實際欄位,而是直接產生資料後傳遞給Widget使用,(這樣的資料稱為引數,它的承接欄位在物件類,物件外看不到,但傳入函數物件內後,也可能處理完後就將資料拋棄掉也說不一定,在設計上都是可以的。)
但實際上要使用Array/List應該是這樣...
List<資料類別> array = List();
List<資料類別> array1 = [資料, 資料, ....];
List<資料類別> array2 = List(數量);
Array/List其實是種物件,所以除了設置欄位以外,需要「產生一個Array/List資料」,然後才用這個Array/List資料來存放資料。(「存放」是Array/List的一個函數。)
為什麼會要寫成Array/List?
因為「一個欄位可以存放多筆資料」是程式語言發展中很重要的概念之一,(大概和函數或物件導向不相上下,)但怎麼做到這件事情在程式語言中產生了兩種分歧。
一種是「這個欄位可以存放的資料數目固定」,一種就是相對的「這個欄位可以存放的資料數目不固定」,前者通常稱為Array(矩陣/陣列),後者稱為List(容器),前者在發展初期比較快成熟,在主流的程式語言(C/C++/Java...)中都預設使用這物件,但後來List越來越成熟,不只主流程式語言也開始支援,甚至有些程式語言(例如Flutter)乾脆直接只建立了List,但又在它們的List上保留了一些Array的特性跟形式。
比如上面有寫到的三種用法中的第二種。沒有Array/List的建構子,直接使用「[]」然後將資料包圍在裏頭。
[資料, 資料, ....];
如果不好理解,那就大概是「產生Array/List並同時塞入資料,一次完成」這樣的概念。
而第三種用法就是指定它的長度、限制它可以存放的資料數目。這就是Array的特性。
要怎麼新增資料、又將資料取出?下面主要有兩種方法(這裡有官方完整制式工程文件。)
List<資料類型> array = List();
array.add(資料);
List<資料類型> array1 = List(5);
array[0] = 資料1;
array[1] = 資料2;
array[2] = 資料3;
array[3] = 資料4;
array[4] = 資料5;
注意看!Array/List內標記「第幾筆資料」是從0開始,常識來說,我們認為所謂的「第一筆資料」在Array/List中是「0」。
這兩種方法有什麼差?
Array/List有「長度」這個屬性,(可以用函數length取得,)如果用第二種方法,整個Array/List長度是不能改變的,(甚至可以說每一筆資料其實已經存在,只是預設指向「不存在任何東西」,)但如果用第一種卻可以中途改變,例如在執行「add」(放入資料)以前,它的長度是0,但之後就變成1。
為什麼Array/List可以做到這種事情?其中一種方法就是利用一整個區段的記憶體配置來指引程式去找到個別資料實際存放的記憶體。而這個「區段」在記憶體中就大概類似物件,「從記憶體欄位N到記憶體欄位N+X之間是這個Array/List的資料。」
所以回頭看看一開始的題目:設置一個函數來取用圖片。
Array<Image> imgs = [img1, img2, img3];
Image getImage(int index){
(如果index小於imgs的長度)
return imgs[index];
}
但這裡有個奇妙的問題:
如何快速且大量的檢視整個Array/List內的資料?例如全部每一筆?
這問題其實可以換個方向來看,首先是:
如何快速且大量的重複做一件事?
這件事情在程式設計中稱為「迴圈」。
迴圈其實是種概念,做法也不只一種,但基本的做法是「for迴圈」。
for(執行多少次的條件){
}
這裡有個「執行多少次的條件」,快速舉兩個例子來讓大家直覺去理解...
for(int i = 0 ; i < 10 ; i++){
}
for(int i = 9 ; i >= 0 ; i--){
}
兩個迴圈都會「{}」裡面寫入的程式執行十次,而這兩個迴圈都有個資料i,在迴圈外無法取得這個i,迴圈結束、i就消失了。
「i++」是i指這個參數在迴圈每執行一次時會增加1,一開始時是0,執行到最後會變成9。
反應快的人可能注意到了「i < 10」就是這個迴圈結束的控制條件,(理論上)其實一開始迴圈並不知道要執行幾次,而是每次執行完檢查i是否還小於10,如果不小於10就結束執行。
而「i--」是i指這個參數在迴圈每執行一次時會減少1,一開始時是9,執行到最後會變成0。
利用迴圈和它的i就可以快速達到檢視整個Array/List內的每一筆。
Array array = [......];
for(int i = 0 ; i < array.length(); i++){
array[i] = ...
}